#ifndef ALFS_POINTERS_DESTRUCTION_EVENT_SOURCE_HPP
#define ALFS_POINTERS_DESTRUCTION_EVENT_SOURCE_HPP
#include    <alfs/config.hpp>

// File [alfs/pointers/destructionEvent::Source.hpp].
//
// Class alfs::destructionEvent::Source.
// Class alfs::DestructionEventWrapper.
// Mainly for use with CheckingPtr<>.
//
// (c) copyright Alf P. Steinbach 2008.
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php>.

namespace alfs{

    namespace detail{
        template< typename T > class AutoClearingRefCountedDeleter;     // Forward.
    }  // detail

    namespace destructionEvent
    {
        class Consumer;

#       define  ThisClass   Source

        class ThisClass
        {
        //template< typename T > friend class detail::AutoClearingRefCountedDeleter;
        friend class Consumer;

        public:
            struct IHandler
            {
                virtual void onReferredObjectDestroyed() = 0;
            };

        private:
            IHandler*   myHandler;

            void setHandler( IHandler& handler )    { myHandler = &handler;  }
            void clearHandler()                     { myHandler = 0;         }

        public:
            virtual ~ThisClass()
            {
                if( myHandler != 0 ) { myHandler->onReferredObjectDestroyed(); }
            }

            ThisClass(): myHandler(0) {}

            ThisClass( ThisClass const& )
            {
                // Nothing, because event receiver only wants event from this object.
            }

            ThisClass& operator=( ThisClass const& )
            {
                // Nothing, because event receiver only wants event from this object.
                return *this;
            }
        };
#       undef   ThisClass


        class Consumer
        {
        protected:
            static void connect( Source& eventSource, Source::IHandler& handler )
            {
                eventSource.setHandler( handler );
            }

            static void disconnect( Source& eventSource )
            {
                eventSource.clearHandler();
            }
        };
    }  // destructionEvent


#   define  ThisClass       DestructionEventWrapper

    template< typename T >
    class DestructionEventWrapper
        : public T
        , public destructionEvent::Source // Last constructed, first destroyed.
    {
    private:
        ThisClass( ThisClass const& );              // No such.
        ThisClass& operator=( ThisClass const& );   // No such.

    public:
        typedef T BaseClass;

        // This constructor is not instantiated if it's not used (we're in magic template
        // world).  I.e. it does not impose a requirement of T being default-constructible.
        ThisClass()
            // : BaseClass(), destructionEvent::Source()   // Causes MSVC 7.1 to misbehave in debug build.
        {}

        virtual ~ThisClass() {}

        template< typename U >
        ThisClass( U const& u )
            : BaseClass( u )
        {}

        template< typename U, typename V >
        ThisClass( U const& u, V const& v )
            : BaseClass( u, v )
        {}

        template< typename U, typename V, typename W >
        ThisClass( U const& u, V const& v, W const& w )
            : BaseClass( u, v, w )
        {}

        template< typename U, typename V, typename W, typename X >
        ThisClass( U const& u, V const& v, W const& w, X const& x )
            : BaseClass( u, v, w, x )
        {}

        template< typename U, typename V, typename W, typename X, typename Y >
        ThisClass( U const& u, V const& v, W const& w, X const& x, Y const& y )
            : BaseClass( u, v, w, x, y )
        {}
    };
#   undef   ThisClass

    template< typename T >
    struct WithDestructionEventWrapper
    {
        typedef 
            typename boost::mpl::if_<
                            alfs::IsConvertibleFromTo<T*, destructionEvent::Source*>,
                            T,
                            DestructionEventWrapper<T>
                            >::type
            Type;
    };

    template< typename T >
    struct SansDestructionEventWrapper
    {
        typedef T   Type;
    };

    template< typename T >
    struct SansDestructionEventWrapper< DestructionEventWrapper< T > >
    {
        typedef T   Type;
    };

}  // alfs

#endif
